"""用户认证模块的测试用例

测试用户注册、登录、权限验证等功能。
"""

import json
from django.test import TestCase, TransactionTestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.db import transaction
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken
from unittest.mock import patch

from .models import User, UserProfile, LoginHistory
from .serializers import UserRegistrationSerializer, CustomTokenObtainPairSerializer

User = get_user_model()


class UserModelTest(TestCase):
    """用户模型测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.user_data = {
            'username': 'testuser',
            'email': 'test@example.com',
            'password': 'testpass123',
            'first_name': 'Test',
            'last_name': 'User'
        }
    
    def test_create_user(self):
        """测试创建普通用户"""
        user = User.objects.create_user(
            username=self.user_data['username'],
            email=self.user_data['email'],
            password=self.user_data['password']
        )
        
        self.assertEqual(user.username, self.user_data['username'])
        self.assertEqual(user.email, self.user_data['email'])
        self.assertTrue(user.check_password(self.user_data['password']))
        self.assertTrue(user.is_active)
        self.assertFalse(user.is_staff)
        self.assertFalse(user.is_superuser)
    
    def test_create_superuser(self):
        """测试创建超级用户"""
        admin_user = User.objects.create_superuser(
            username='admin',
            email='admin@example.com',
            password='adminpass123'
        )
        
        self.assertEqual(admin_user.username, 'admin')
        self.assertTrue(admin_user.is_active)
        self.assertTrue(admin_user.is_staff)
        self.assertTrue(admin_user.is_superuser)
    
    def test_user_string_representation(self):
        """测试用户字符串表示"""
        user = User.objects.create_user(
            username=self.user_data['username'],
            email=self.user_data['email'],
            password=self.user_data['password']
        )
        
        self.assertEqual(str(user), f"{self.user_data['username']} ({self.user_data['email']})")
    
    def test_user_profile_creation(self):
        """测试用户配置自动创建"""
        user = User.objects.create_user(
            username=self.user_data['username'],
            email=self.user_data['email'],
            password=self.user_data['password']
        )
        
        # 检查是否自动创建了用户配置
        self.assertTrue(hasattr(user, 'profile'))
        self.assertIsInstance(user.profile, UserProfile)


class UserRegistrationTest(APITestCase):
    """用户注册测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.client = APIClient()
        self.register_url = reverse('authentication:auth-register')
        self.valid_user_data = {
            'username': 'newuser',
            'email': 'newuser@example.com',
            'password': 'newpass123',
            'password_confirm': 'newpass123',
            'first_name': 'New',
            'last_name': 'User'
        }
    
    def test_valid_user_registration(self):
        """测试有效用户注册"""
        response = self.client.post(
            self.register_url,
            self.valid_user_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertTrue(User.objects.filter(username='newuser').exists())
        
        # 检查返回数据
        self.assertIn('user', response.data)
        self.assertEqual(response.data['user']['username'], 'newuser')
        self.assertEqual(response.data['user']['email'], 'newuser@example.com')
    
    def test_duplicate_username_registration(self):
        """测试重复用户名注册"""
        # 先创建一个用户
        User.objects.create_user(
            username='newuser',
            email='existing@example.com',
            password='pass123'
        )
        
        response = self.client.post(
            self.register_url,
            self.valid_user_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('username', response.data)
    
    def test_duplicate_email_registration(self):
        """测试重复邮箱注册"""
        # 先创建一个用户
        User.objects.create_user(
            username='existinguser',
            email='newuser@example.com',
            password='pass123'
        )
        
        response = self.client.post(
            self.register_url,
            self.valid_user_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('email', response.data)
    
    def test_password_mismatch_registration(self):
        """测试密码不匹配注册"""
        invalid_data = self.valid_user_data.copy()
        invalid_data['password_confirm'] = 'differentpass'
        
        response = self.client.post(
            self.register_url,
            invalid_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('password_confirm', response.data)
    
    def test_weak_password_registration(self):
        """测试弱密码注册"""
        invalid_data = self.valid_user_data.copy()
        invalid_data['password'] = '123'
        invalid_data['password_confirm'] = '123'
        
        response = self.client.post(
            self.register_url,
            invalid_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('password', response.data)


class UserLoginTest(APITestCase):
    """用户登录测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.client = APIClient()
        self.login_url = reverse('authentication:token_obtain_pair')
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_valid_login(self):
        """测试有效登录"""
        login_data = {
            'email': 'test@example.com',
            'password': 'testpass123'
        }
        
        response = self.client.post(
            self.login_url,
            login_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('access', response.data)
        self.assertIn('refresh', response.data)
        self.assertIn('user', response.data)
    
    def test_invalid_email_login(self):
        """测试无效邮箱登录"""
        login_data = {
            'email': 'wrong@example.com',
            'password': 'testpass123'
        }
        
        response = self.client.post(
            self.login_url,
            login_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
    
    def test_invalid_password_login(self):
        """测试无效密码登录"""
        login_data = {
            'email': 'test@example.com',
            'password': 'wrongpass'
        }
        
        response = self.client.post(
            self.login_url,
            login_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
    
    def test_inactive_user_login(self):
        """测试非活跃用户登录"""
        self.user.is_active = False
        self.user.save()
        
        login_data = {
            'email': 'test@example.com',
            'password': 'testpass123'
        }
        
        response = self.client.post(
            self.login_url,
            login_data,
            format='json'
        )
        
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)


class UserAuthenticationTest(APITestCase):
    """用户认证测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.client = APIClient()
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        self.refresh = RefreshToken.for_user(self.user)
        self.access_token = str(self.refresh.access_token)
    
    def test_authenticated_request(self):
        """测试认证请求"""
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.access_token}')
        
        response = self.client.get(reverse('authentication:user-me'))
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['username'], 'testuser')
    
    def test_unauthenticated_request(self):
        """测试未认证请求"""
        response = self.client.get(reverse('authentication:user-me'))
        
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
    
    def test_invalid_token_request(self):
        """测试无效token请求"""
        self.client.credentials(HTTP_AUTHORIZATION='Bearer invalid_token')
        
        response = self.client.get(reverse('authentication:user-me'))
        
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)


class LoginHistoryTest(TransactionTestCase):
    """登录历史测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_login_history_creation(self):
        """测试登录历史记录创建"""
        with transaction.atomic():
            login_history = LoginHistory.objects.create(
                user=self.user,
                ip_address='127.0.0.1',
                user_agent='Test Browser',
                is_successful=True
            )
        
        self.assertEqual(login_history.user, self.user)
        self.assertEqual(login_history.ip_address, '127.0.0.1')
        self.assertTrue(login_history.is_successful)
    
    def test_failed_login_history(self):
        """测试失败登录历史记录"""
        with transaction.atomic():
            login_history = LoginHistory.objects.create(
                user=self.user,
                ip_address='127.0.0.1',
                user_agent='Test Browser',
                is_successful=False,
                failure_reason='Invalid password'
            )
        
        self.assertFalse(login_history.is_successful)
        self.assertEqual(login_history.failure_reason, 'Invalid password')


class UserProfileTest(TransactionTestCase):
    """用户配置测试"""
    
    def setUp(self):
        """设置测试数据"""
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_user_profile_creation(self):
        """测试用户配置创建"""
        with transaction.atomic():
            profile = UserProfile.objects.create(
                user=self.user,
                editor_theme='vs-dark'
            )
        
        self.assertEqual(profile.user, self.user)
        self.assertEqual(profile.editor_theme, 'vs-dark')
    
    def test_user_profile_update(self):
        """测试用户配置更新"""
        with transaction.atomic():
            profile = UserProfile.objects.create(user=self.user)
            profile.editor_theme = 'vs'
            profile.auto_save_interval = 60
            profile.save()
        
        updated_profile = UserProfile.objects.get(user=self.user)
        self.assertEqual(updated_profile.editor_theme, 'vs')
        self.assertEqual(updated_profile.auto_save_interval, 60)
